---------------------------------------------------------------------------------
  -- Design Name : CPU
  -- File Name   : cpu.vhd
  -- Function    : Top-level design entity
  -- Authors     : Mirko Francuski  2006/0225
  --               Milos Mihajlovic 2006/0039
  -- School      : University of Belgrade
  --               School for Electrical Engineering
  --               Department for Computer Engineering and Information Theory
  -- Subject     : VLSI Computer Systems
---------------------------------------------------------------------------------

library ieee;

use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
use work.UserPkg.all;

entity CPU is
  port (
    clock   : in     std_logic;
    start   : in     std_logic;
    reset   : in     std_logic;
    diBUS   : in     Word32;
    halt    : out    std_logic;
    iRd     : out    std_logic;
    dRd     : out    std_logic;
    dWr     : out    std_logic;
    aiBUS   : out    Word32 := (others => 'Z');
    adBUS   : out    Word32 := (others => 'Z');
    ddBUS   : inout  Word32 := (others => 'Z')
  );
end;

architecture behavioral of CPU is
  signal opId2R         : OpCode;
  signal opR2ExMem      : OpCode;
  signal opExMem2R      : OpCode;
  signal opR2Wb         : OpCode;
  
  signal rdAddrId2R     : RegAddr;
  signal rdAddrR2ExMem  : RegAddr;
  signal rdAddrExMem2R  : RegAddr;
  signal rdAddrR2Wb     : RegAddr;
  signal rdId2R         : RegAddr;
  signal rdR2ExMeM      : RegAddr;
  signal rwrWb          : RegAddr;
  signal rs1AddrId2R    : RegAddr;
  signal rs2AddrId2R    : RegAddr;
  signal rs1AddrR2ExMem : RegAddr;
  signal rs2AddrR2ExMem : RegAddr;
  
  signal newPCIf2R      : Word32;
  signal newPCR2Id      : Word32;
  signal newAddrIdOut   : Word32;
  signal newAddrExMemIn : Word32;
  signal aiBusOut       : Word32;
  signal adBusOut       : Word32;
  signal ddBusOut       : Word32;
  signal wbData         : Word32;
  signal rs1DataId2R    : Word32;
  signal rs2DataId2R    : Word32;
  signal rs1DataR2ExMem : Word32;
  signal rs2DataR2ExMem : Word32;
  signal stackExMem2R   : Word32;
  signal stackR2Wb      : Word32;
  signal aluDataExMem2R : Word32;
  signal aluDataR2Wb    : Word32;
  
  signal clk            : std_logic;
  signal branchTaken    : std_logic;
  signal loRTS          : std_logic;
  signal stall          : std_logic;
  signal halt2          : std_logic;
  signal wr             : std_logic;
  signal rwr16          : std_logic;
  signal idleR2ExMem    : std_logic;
  signal idleExMem2R    : std_logic;
  signal aiBusReq       : std_logic := '0';
  signal adBusReq       : std_logic := '0';
  signal ddBusReq       : std_logic := '0';
  signal workSignal     : std_logic := '0';
  signal resetSignal    : std_logic;
  
  signal wrkOutIfS      : std_logic;
  signal wrkOutRIfId    : std_logic;       
  signal wrkOutIdS      : std_logic;
  signal wrkOutRIdExMem : std_logic;
  signal wrkOutExMemS   : std_logic;
  signal wrkOutRExMemWb : std_logic;
  signal wrkOutWbS      : std_logic;
  
begin
	
  resetSignal <= reset or start;    
  clk <= clock;
  halt <= not (workSignal or wrkOutWbS);
  iRd <= aiBusReq;
  
  process(clock,start,halt2)
  begin
    if (falling_edge(clock)) then
      if(start = '1') then
        workSignal <= '1';
      elsif (halt2 = '1') then
        workSignal <= '0';      
      end if;
    end if;
  end process;
    
  ifS: IfStage port map (
    clk           => clk,
    wrkIn         => workSignal and not halt2,
    wrkOut        => wrkOutIfS,
    branchTaken   => branchTaken,
    loRTS         => loRTS,
    stall         => stall,
    reset         => resetSignal,
    newAddr       => newAddrIdOut,
    wbOut         => wbData,
    newPC         => newPCIF2R,
    aiBusReq      => aiBusReq,
    aiBUS         => aiBusOut
  );
  
  rIfId: R_If_Id port map (
    clk           => clk,
    reset         => resetSignal,
    wrkIn         => wrkOutIfS,
    wrkOut        => wrkOutRIfId,
    stall         => stall,
    newAddrIn     => newPCIF2R,
    newAddrOut    => newPCR2ID
  );
  
  idS: IdStage port map (
    clk           => clk,
    wrkIn         => wrkOutRIfId,
    wrkOut        => wrkOutIdS,
    newPC         => newPCR2ID,
    DIBus         => diBus,
    wr            => wr,
    rwr           => rwrWb,
    rwr16         => rwr16,
    wbData        => wbData,
    prevOp        => opR2ExMem,
    prevRdAddr    => rdR2ExMeM,
    reset         => resetSignal,
    op            => opId2R,
    rdAddr        => rdId2R,
    newAddr       => newAddrIdOut,
    rs1Data       => rs1DataId2R,
    rs2Data       => rs2DataId2R,
    idle          => branchTaken,
    stall         => stall,
    halt          => halt2,
    rs1Addr       => rs1AddrId2R,
    rs2Addr       => rs2AddrId2R
  );
  
  rIdExMem: R_Id_ExMem port map (
    clk           => clk,
    reset         => resetSignal,
    wrkIn         => wrkOutIdS,
    wrkOut        => wrkOutRIdExMem,
    stall         => stall,
    idleIn        => branchTaken,
    idleOut       => idleR2ExMem,
    newAddrIn     => newAddrIdOut,
    newAddrOut    => newAddrExMemIn,
    rs1DataIn     => rs1DataId2R,
    rs1DataOut    => rs1DataR2ExMem,
    rs2DataIn     => rs2DataId2R,
    rs2DataOut    => rs2DataR2ExMem,
    opIn          => opId2R,
    opOut         => opR2ExMem,
    rdAddrIn      => rdId2R,
    rdAddrOut     => rdR2ExMeM,
    r1AddrIn      => rs1AddrId2R,
    r1AddrOut     => rs1AddrR2ExMem,
    r2AddrIn      => rs2AddrId2R,
    r2AddrOut     => rs2AddrR2ExMem
  );
  
  exMemS: ExMemStage port map (
    clk           => clk,
    wrkIn         => wrkOutRIdExMem,
    wrkOut        => wrkOutExMemS,
    idleIn        => idleR2ExMem,
    reset         => resetSignal,
    wr            => wr,
    newAddr       => newAddrExMemIn,
    rs1Data       => rs1DataR2ExMem,
    rs2Data       => rs2DataR2ExMem,
    wbData        => wbData,
    r1addr        => rs1AddrR2ExMem,
    r2addr        => rs2AddrR2ExMem,
    rwr           => rwrWb,
    rd            => rdR2ExMeM,
    op            => opR2ExMem,
    adBusReq      => adBusReq,
    ddBusReq      => ddBusReq,
    opOut         => opExMem2R,
    rdOut         => rdAddrExMem2R,
    aluData       => aluDataExMem2R,
    adBus         => adBusOut,
    ddBus         => ddBusOut,
    stackData     => stackExMem2R,
    dRd           => dRd,
    dWr           => dWr
  );
  
  rExMemWb: R_ExMem_Wb port map (
    clk           => clk,
    reset         => resetSignal,
    wrkIn         => wrkOutExMemS,
    wrkOut        => wrkOutRExMemWb,
    stall         => stall,
    aluDataIn     => aluDataExMem2R,
    aluDataOut    => aluDataR2Wb,
    stackDataIn   => stackExMem2R,
    stackDataOut  => stackR2Wb,
    rdIn          => rdAddrExMem2R,
    rdOut         => rdAddrR2Wb,
    opIn          => opExMem2R,
    opOut         => opR2Wb
  );
  
  wbS: WbStage port map (
    clk           => clk,
    wrkIn         => wrkOutRExMemWb,
    wrkOut        => wrkOutWbS,
    op            => opR2Wb,
    aluOut        => aluDataR2Wb,
    DDBus         => ddBus,
    stackOut      => stackR2Wb,
    rd            => rdAddrR2Wb,
    wbData        => wbData,
    wr            => wr,
    rwr           => rwrWb,
    rwr16         => rwr16,
    loRts         => loRTS
  );
  
  aiBusTSB: GenTsb port map (
    request       => aiBusReq,
    datain        => aiBusOut,
    dataout       => aiBus
  );
    
  adBusTSB: GenTsb port map (
    request       => adBusReq,
    datain        => adBusOut,
    dataout       => adBus
  );
  
  ddBusTSB: GenTsb port map (
    request       => ddBusReq,
    datain        => ddBusOut,
    dataout       => ddBus
  ); 
  
end architecture behavioral;